package com.baiyuan.tms.gateway.core.filter;


import com.alibaba.fastjson.JSONObject;
import com.baiyuan.tms.gateway.core.common.dtos.ResponseResult;
import com.baiyuan.tms.gateway.core.config.GatewayConfig;
import com.baiyuan.tms.gateway.core.dto.TokenObject;
import com.baiyuan.tms.gateway.core.enums.KeyEnum;
import com.baiyuan.tms.gateway.core.utils.JwtUtils;
import com.baiyuan.tms.gateway.core.utils.Payload;
import com.baiyuan.tms.gateway.core.utils.RedisUtil;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import sun.misc.BASE64Decoder;

import java.net.URLEncoder;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReference;

/**
 * JWT filter
 */
@Component
@Slf4j
public class JwtTokenFilter implements GlobalFilter, Ordered{

  /*  @Resource
    private  final RedisTemplate<String,String> redisTemplate;*/


    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private GatewayConfig gatewayConfig;

    @Value("${baiyuan.jwtsecret}")
    public  String JWT_SECRET ;

/*    public JwtTokenFilter(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }*/

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String url = exchange.getRequest().getURI().getPath();
        //跳过不需要验证的路径
        boolean matchUrl = Arrays.stream(gatewayConfig.getUrls())
                .anyMatch(url::contains);
        if(matchUrl){
            return chain.filter(exchange);
//                    });
        }
        if(null != gatewayConfig.getUrls()&& Arrays.asList(gatewayConfig.getUrls()).contains(url)){
            return chain.filter(exchange);
        }
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        ServerHttpResponse resp = exchange.getResponse();
        if(Strings.isNullOrEmpty(token))
            return authError(resp);
        try {
//            PublicKey publicKey = RsaUtils.getPublicKey("usr/local/key/a.txt");
            PublicKey publicKey = getPublicKey(KeyEnum.publicKeyFilename.getCode());
            Payload<TokenObject> payload = JwtUtils.getInfoFromToken(token, publicKey, TokenObject.class);

            //获取登录用户信息
            TokenObject tokenObject = payload.getInfo();
            String s = (String) redisUtil.get(tokenObject.getAccount()+tokenObject.getOrigin());
                if (s==null) {
                    return authError(resp);
                }

            //向headers中放用户id
            ServerHttpRequest request = exchange.getRequest().mutate()
                    .header("userId", tokenObject.getId()+"")
                    .header("userName", URLEncoder.encode(tokenObject.getName(), "utf-8"))
                    .header("zj",URLEncoder.encode(tokenObject.getOrigin(), "utf-8"))
                    .header("phone",URLEncoder.encode(tokenObject.getPhone(), "utf-8"))
//                    .header("branch",URLEncoder.encode(tokenObject.getBranch(), "utf-8"))
//                    .header("branchId",tokenObject.getBranchId()+"", "utf-8")
                    .build();
            return chain.filter(exchange.mutate().request(request).build());
        } catch (Exception e) {
    e.printStackTrace();
            return authError(resp);
        }
    }

    @Override
    public int getOrder() {
        return -100;
    }

    /**
     * 认证错误输出
     * @param resp 响应对象
     * @return
     */
    private Mono<Void> authError(ServerHttpResponse resp) {
        byte[] bytes = JSONObject.toJSONString(ResponseResult.errorResult(401,"token已过期")).getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = resp.bufferFactory().wrap(bytes);
        return resp.writeWith(Mono.just(buffer));
    }

    private Mono<Void> authErrorT(ServerHttpResponse resp) {
        byte[] bytes = JSONObject.toJSONString(ResponseResult.errorResult(401,"token验证失败")).getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = resp.bufferFactory().wrap(bytes);
        return resp.writeWith(Mono.just(buffer));

    }

    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest)
    {
        // 获取请求体
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        AtomicReference<String> bodyRef = new AtomicReference<>();
        body.subscribe(buffer -> {
            CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
            DataBufferUtils.release(buffer);
            bodyRef.set(charBuffer.toString());
        });
        return bodyRef.get();
    }

    private static PublicKey getPublicKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = (new BASE64Decoder()).decodeBuffer(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }


}
